<template>
  <div class="article-container">
    <!-- 导航栏 -->
    <van-nav-bar
      class="page-nav-bar"
      fixed
      @click-left="$router.back()"
      left-arrow
      title="黑马头条"
    >
    </van-nav-bar>
    <!-- /导航栏 -->

    <!-- 内容区域 -->
    <div class="main-wrap">
      <!-- 加载中 -->
      <div class="loading-wrap" v-if="loading">
        <van-loading color="#3296fa" vertical>加载中</van-loading>
      </div>
      <!-- /加载中 -->

      <!-- 加载完成-文章详情 -->
      <div class="article-detail" v-else-if="article.title">
        <!-- 文章标题 -->
        <h1 class="article-title">{{ article.title }}</h1>
        <!-- /文章标题 -->

        <!-- 用户信息 -->
        <van-cell class="user-info" center :border="false">
          <!-- 左侧图标插槽 -->
          <van-image
            class="avatar"
            slot="icon"
            round
            fit="cover"
            :src="article.aut_photo"
          />
          <!-- 标题插槽 -->
          <div slot="title" class="user-name">{{ article.aut_name }}</div>
          <!-- 描述信息插槽 -->
          <div slot="label" class="publish-date">
            {{ article.pubdate | relativeTime }}
          </div>
          <!-- 右侧默认插槽 -->
          <!-- <van-button
            class="follow-btn" type="info" slot="default"
            color="#3296fa" round  size="small" icon="plus"
            @click="onFollow" v-if="!article.is_followed"
            >关注 {{ article.is_followed }}</van-button
          >
          <van-button
            class="follow-btn" round size="small" v-else
            @click="onFollow"
          >已关注 {{ article.is_followed }}</van-button> -->
          <follow-user
          :isFollowed.sync="article.is_followed" :userId="article.aut_id"
          ></follow-user>
        </van-cell>
        <!-- /用户信息 -->

        <!-- 文章内容 -->
        <!-- v-html="article.content" -->
        <div
          ref="article-content"
          class="article-content markdown-body"
        ></div>

        <van-divider>正文结束</van-divider>

        <!-- 评论列表 -->
        <comment-list ref="comment-list"
        :sourceId="article.art_id" @onload-success="onloadSuccessFn"
        @reply-click="onReplyClick"
        ></comment-list>
        <!-- /评论列表 -->

      </div>
      <!-- /加载完成-文章详情 -->

      <!-- 加载失败：404 -->
      <div class="error-wrap" v-else-if="errStatus === 404">
        <van-icon name="failure" />
        <p class="text">该资源不存在或已删除！</p>
      </div>
      <!-- /加载失败：404 -->

      <!-- 加载失败：其它未知错误（例如网络原因或服务端异常） -->
      <div class="error-wrap" v-else>
        <van-icon name="failure" />
        <p class="text">内容加载失败！</p>
        <van-button class="retry-btn" @click="loadArticleInfo"
          >点击重试</van-button
        >
      </div>
      <!-- /加载失败：其它未知错误（例如网络原因或服务端异常） -->
    </div>

    <!-- 底部区域 -->
    <div class="article-bottom">
      <van-button class="comment-btn" type="default" round size="small"
      @click="isPostShow = true"
      >写评论</van-button>

      <!-- 评论数量展示 -->
      <van-icon name="comment-o" :badge="totalCommentCount" color="#777" />

      <!-- 关注文章 -->
      <collect-article
      :isCollected.sync="article.isCollected"
      :artId="article.art_id"
      ></collect-article>

      <!-- 点赞文章 -->
      <lick-article
      :attitude.sync="article.attitude"
      :artId="article.art_id"
      ></lick-article>

      <!-- 转发文章 -->
      <van-icon name="share" color="#777777"></van-icon>
    </div>
    <!-- /底部区域 -->

    <!-- 文章评论弹出层 -->
    <van-popup v-model="isPostShow" position="bottom">
      <comment-post
      :targetId="article.art_id"
      @post-success="onPostSuccess"
      ></comment-post>
    </van-popup>

    <!-- 评论回复弹框 -->
    <!--
        van-popup组件第一次开启的时候,会将dom元素挂载到真实dom树上,但当关闭它时只会通过display:none 去隐藏该弹窗,所以探矿中的所有变量就与状态并不会重置
      1. 在初始化页面时,状态值为false,弹框并不会渲染到dom树上
      2. 当状态值改变为true时,弹出的内容渲染到dom 树上
      3. 在运行过程中,通过状态切换来改变弹框的显示或隐藏时,仅是通过dislapy:none来进行的,也就说,弹框的内容并不会被销毁
      4. 当在此以不同的数据显示时，就极有可能有部分内容并不更新
      => display: none;的显示和隐藏 => v-show => 把弹框内部的内容通过v-if来进行dom树上的删除
      => 解决办法
      1. 如果弹框内容只有一个标签时，为标签设置v-if属性
      2. 如果弹框内容有多个标签时，将所有的内容用<template>标签所包裹，给<template>标签设置v-if
     -->
    <van-popup
    v-model="isReplyShow" position="bottom" style="height:100%"
    >
     <template v-if="isReplyShow">
        <comment-reply
      @close="isReplyShow = false" :comment="currentComment"
        ></comment-reply>
     </template>
    </van-popup>
  </div>
</template>

<script>
/*
  $router => 路由的跳转功能 .back .push
  $route => 获取路由参数的方法 .query .params
*/
/*
  目标1： 处理加载内容 - 加载状态、文章内容、错误提示
  1. 创建一个loading状态变量，来控制当前页面数据的加载
  2. 通过article文章详情对象中的任意一个属性的存在来判断接口数据是否请求成功， 如article.title
  3. 如果没有请求成功，那么通过catch报错信息中返回的error.response.status是否等于404来确定到底显示哪一个错误提示盒子
  4. 请求错误时，的点击重试按钮设置点击事件重新调用 loadArticleInfo 方法
*/
/*
  目标2：文章详情正文的样式结构
  场景：发现在后端返回的正文富文本中，每一个不同要素的标签都有统一的一些列类名来表现。
  在正常的工作当中，应该根据产品经理提出的样式规范，来通过这些设置好的类名进行样式布局，一般情况下这种富文本结构样式的自定义配置单人可能会需要5~10个工作日才能完成

  我们发现这种正文部分其实与mackdown文件非常相似，可以考虑看看网上有没有对应mackdown文本现成的样式表，直接拿到当前页面上来使用（可能别人的样式表中的class类名与我们后端设计的类名不同，需要做单独处理 - 一般单人需要1~2个工作日）

  使用方式：
  1. 需要给当前组件中设置样式内容的父标签配置上专属的样式名称 markdown-body
  2. 在组件中局部引入样式表 @import
  3. 因为 .postcssrc.js 配置文件影响了全局样式的px比例问题，所以需要去忽略第三方提供的样式类型
*/
/*
  目标3：查看文章中的大图
  1. 我们明确了使用vant 组件中的图片预览ImagePreview， 通过其中的images数组属性来放置所有的文本图片路径，通过startPosition索引属性，来设置当前展开的图片
  2. 等待获取文章详情后所有的dom渲染完成后，去通过ref和$refs去页面上找到文章正文的父标签
  3. 找到之后，通过获取该父组件内部所有img标签的方式来返回图片列表（$refs元素对象.querySelectorAll('img')）
  4. 拿到的数组结构是伪数组，需要用[...伪数组]的形式进行真数组的转化
  5. 然后将该数组中的src图片路径转化为 ImagePreview组件中 images里的路径数组

  通过2-5步，就已经完成了images数组结构

  6. 为每一张图片绑定点击事件，该点击事件的逻辑部分（showImage示例方法）
  7. 通过图片当前所在数组的索引设置startPosition属性
*/
/*
  目标4：关注作者
  1. 使用文章详情接口提供的状态变量(is_followed)，该变量的用途是切换已关注状态与未关注状态
  2. 当点击已关注时，会调用接口将后端状态改为未关注状态，相反毅然
  3. 当报错信息为400时，表示自己关注了自己，不允许，需要用特殊提示语提示用户
*/
/*
  目标5：文章收藏
  发现除了页面样式和接口以外，其他的业务逻辑与关注用户组件完全一致，那么尝试通过关注用户组件来对 文章收藏组件进行集成
  1. 复制完成后，将template模块内容进行替换
  2. 替换当前组件中具有实际意义的变量，在当前组件的全局进行统一替换
  3. 替换当前业务接口
  4. 通过状态变量对template模块组件进行动态切换操作
*/

import { getArticleByIdAPI } from '../../api/index.js'
import { ImagePreview } from 'vant'
import FollowUser from '../../components/follow-user.vue'
import CollectArticle from '../../components/collect-article.vue'
import LickArticle from '../../components/lick-article.vue'
import CommentList from './components/comment-list.vue'
import CommentPost from './components/comment-post.vue'
import CommentReply from './components/comment-reply.vue'
export default {
  name: 'ArticleIndex',
  components: {
    FollowUser,
    CollectArticle,
    LickArticle,
    CommentList,
    CommentPost,
    CommentReply
  },
  props: {
    // 在路由规则数组中设置了porps：true时，就可以在组件的props属性中获取路由传递过来的参数了
    articleId: {
      // 文章id
      type: String,
      default: ''
    }
  },
  // 给所有的后代组件提供数据
  // 与data的写法一样,在provide中定义的参数,就可以发送给所有的子组件
  // 注意：不要滥用
  provide () {
    return {
      articleIdG: this.articleId
    }
  },
  data () {
    return {
      article: {}, // 文章详情参数
      loading: true, // 加载中的 loading 状态,默认开启加载状态,当请求接口完成后悔主动关闭
      errStatus: 0, // 失败的状态码默认为0,主要是去判断是否为404
      // btnLoading: false
      totalCommentCount: 0, // 文章评论总数
      isPostShow: false, // 文章评论编辑状态框
      isReplyShow: false, // 评论回复弹框状态
      currentComment: {} // 当前选中的评论内容
    }
  },
  created () {
    // 调用获取文章详情方法
    this.loadArticleInfo()
  },
  methods: {
    // 开启回复弹窗
    onReplyClick (event) {
      // 开启回复弹窗时,更新当前评论变量
      this.currentComment = event
      // 开启评论弹窗
      this.isReplyShow = true
    },
    // 提交评论成功
    onPostSuccess (res) {
      // 在评论列表添加新的内容
      this.$refs['comment-list'].unshiftComment(res)
      // 关闭弹窗
      this.isPostShow = false
    },
    onloadSuccessFn (total) {
      this.totalCommentCount = total
    },
    // async onFollow () {
    //   // 展示关注按钮的loading状态
    //   this.btnLoading = true
    //   try {
    //     if (this.article.is_followed) {
    //       // 已关注，取消关注
    //       await deleteFollowAPI(this.article.aut_id)
    //     } else {
    //       // 没有关注，添加关注
    //       await addFollowAPI(this.article.aut_id)
    //     }
    //     this.article.is_followed = !this.article.is_followed
    //   } catch (err) {
    //     if (err.response && err.response.status === 400) {
    //       this.$toast('自己不能关注自己！')
    //     } else {
    //       this.$toast('操作失败，请重试！')
    //     }
    //     console.log(err)
    //   }
    //   // 关闭关注按钮的loading状态
    //   this.btnLoading = false
    // },
    // // 查看大图示例方法
    // showImage () {
    //   ImagePreview({
    //     images: [
    //       'https://img01.yzcdn.cn/vant/apple-1.jpg',
    //       'https://img01.yzcdn.cn/vant/apple-2.jpg'
    //     ],
    //     startPosition: 1
    //   })
    // },
    // 获取文章详情
    async loadArticleInfo () {
      // 开启加载状态
      this.loading = true
      try {
        const res = await getArticleByIdAPI(this.articleId)
        this.article = res.data.data
        // console.log(this.article)

        // 2.等待获取文章详情后所有dom渲染完成后,去通过ref和$refs去页面上找到文章正文的标签
        // 发现nextTick失效了,其实时因为v-html这个指令的影响
        // this.$nextTick(() => {
        //   console.log(this.$refs['article-content']) // undefined
        // })
        // 用setTomeout将其异步化
        setTimeout(() => {
          // console.log(this.$refs['article-content'])
          this.previewImage()
        }, 0)
      } catch (err) {
        // 请求失败时,判断现在以哪种错误提示框展示
        // 在错误处理时,不一定所有的err都有response属性,所以要在获取status之前
        if (err.response && err.response.status === 400) {
          this.errStatus = 404
        }
        this.$toast('获取失败')
      }
      //  无论成功还是失败,都需要关闭加载状态
      this.loading = false
    },

    // 查看大图的设置
    previewImage () {
      // 因为后端的缘故,导致有很多文章没有图片,或者时图片损坏,我们在'artice-item.vue'跳转到这个文章详情页时,固定它的文章id为7817
      //   3. 找到之后，通过获取该父组件内部所有img标签的方式来返回图片列表（$refs元素对象.querySelectorAll('img')）
      const articleContent = this.$refs['article-content']
      let imgs = articleContent.querySelectorAll('img')
      // 将伪数组转化为真数组
      imgs = [...imgs]
      // console.log(imgs)
      // 5. 然后将该数组中的src图片路径转化为 ImagePreview组件中 images里的路径数组
      const imageSrcList = imgs.map((img) => img.src)
      // console.log(imageSrcList)
      // 6. 为每一张图片绑定点击事件，该点击事件的逻辑部分（showImage示例方法）
      imgs.forEach((img, index) => {
        // 每一个img都是一个dom元素
        img.onclick = () => {
          ImagePreview({
            images: imageSrcList, // 预览图片的合集部分,可以用作切换图片
            // 7. 通过图片当前所在数组的索引设置startPosition属性
            startPosition: index // 当前第一个打开的图片索引,从0 开始计算
          })
        }
      })
    }
  }
}
</script>

<style scoped lang="less">
@import './css/github-markdown.css';
.article-container {
  .page-nav-bar {
    // /deep/
    :deep(.van-icon-arrow-left) {
      color: #fff;
    }
  }

  .main-wrap {
    padding-top: 92px;
    padding-bottom: 88px;
    overflow-y: scroll;
    background-color: #fff;
  }
  .article-detail {
    .article-title {
      font-size: 40px;
      padding: 50px 32px;
      margin: 0;
      color: #3a3a3a;
    }

    .user-info {
      padding: 0 32px;
      .avatar {
        width: 70px;
        height: 70px;
        margin-right: 17px;
      }
      .van-cell__label {
        margin-top: 0;
      }
      .user-name {
        font-size: 24px;
        color: #3a3a3a;
      }
      .publish-date {
        font-size: 23px;
        color: #b7b7b7;
      }
      .follow-btn {
        width: 170px;
        height: 58px;
      }
    }

    .article-content {
      padding: 55px 32px;
      /deep/ p {
        text-align: justify;
      }
    }
  }

  .loading-wrap {
    padding: 200px 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fff;
  }

  .error-wrap {
    padding: 200px 32px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: #fff;
    .van-icon {
      font-size: 122px;
      color: #b4b4b4;
    }
    .text {
      font-size: 30px;
      color: #666666;
      margin: 33px 0 46px;
    }
    .retry-btn {
      width: 280px;
      height: 70px;
      line-height: 70px;
      border: 1px solid #c3c3c3;
      font-size: 30px;
      color: #666666;
    }
  }

  .article-bottom {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    justify-content: space-around;
    align-items: center;
    box-sizing: border-box;
    height: 88px;
    border-top: 1px solid #d8d8d8;
    background-color: #fff;
    .comment-btn {
      width: 282px;
      height: 46px;
      border: 2px solid #eeeeee;
      font-size: 30px;
      line-height: 46px;
      color: #a7a7a7;
    }
    .van-icon {
      font-size: 40px;
      .van-info {
        font-size: 16px;
        background-color: #e22829;
      }
    }
  }
}
</style>
